package com.whfc.mach.service.impl;

import com.whfc.base.param.AppFileExportParam;
import com.whfc.base.service.AppExportService;
import com.whfc.common.exception.BizException;
import com.whfc.common.file.FileHandler;
import com.whfc.common.file.FilePathConfig;
import com.whfc.common.file.properties.FileExpirationRules;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.DateUtil;
import com.whfc.common.util.FileUtil;
import com.whfc.common.util.RandomUtil;
import com.whfc.mach.dao.AppMachMaintainPayMapper;
import com.whfc.mach.dto.maintain.*;
import com.whfc.mach.service.AppMachMaintainReportService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.*;

/**
 * @author sun_guodong
 * @date 2021-08-13
 */
@DubboService(interfaceClass = AppMachMaintainReportService.class, version = "1.0.0")
public class AppMachMaintainReportServiceImpl implements AppMachMaintainReportService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AppMachMaintainPayMapper appMachMaintainPayMapper;

    @Autowired
    private FilePathConfig filePathConfig;

    @Autowired
    private FileHandler fileHandler;

    @DubboReference(interfaceClass = AppExportService.class, version = "1.0.0")
    private AppExportService appExportService;

    private static final String MONTH_REPORT = "设备保养月报";

    private static final String YEAR_REPORT = "设备保养年报";

    private static final String MONTH_REPORT_TIME_FORMAT = "MM-dd";

    private static final String YEAR_REPORT_TIME_FORMAT = "yyyy-MM";

    private static final String SUFFIX = "xls";

    @Override
    public MaintainPayStatDTO maintainPayStat(Integer deptId, Date startDate, Date endDate, String keyword) throws BizException {
        logger.info("统计设备保养费用服务,deptId:{},startDate:{},endDate:{},keyword:{}",
                deptId, startDate, endDate, keyword);
        List<MaintainPayDTO> payDTOList = appMachMaintainPayMapper.selectByDeptId(deptId, startDate, endDate, keyword);
        Map<String, Double> map = new HashMap<>();
        Double payTotal = 0D;
        for (MaintainPayDTO maintainPayDTO : payDTOList) {
            String payName = maintainPayDTO.getPayName();
            Double payValue = maintainPayDTO.getPayValue();
            Double aDouble = map.get(payName);
            if (aDouble == null) {
                map.put(payName, payValue);
            } else {
                map.put(payName, aDouble + payValue);
            }
            payTotal += payValue;
        }

        // 统计各类费用
        List<MaintainPayDTO> payList = new ArrayList<>();
        Set<String> payNameList = map.keySet();
        for (String payName : payNameList) {
            MaintainPayDTO maintainPayDTO = new MaintainPayDTO();
            maintainPayDTO.setPayName(payName);
            maintainPayDTO.setPayValue(map.get(payName));
            payList.add(maintainPayDTO);
        }
        MaintainPayStatDTO data = new MaintainPayStatDTO();
        data.setPayList(payList);
        data.setPayTotal(payTotal);
        return data;
    }

    @Override
    public MaintainMonthReportDTO reportByMonth(Integer deptId, Date startDate, Date endDate, String keyword) throws BizException {
        logger.info("设备保养月报服务,deptId:{},startDate:{},endDate:{},keyword:{}", deptId, startDate, endDate, keyword);

        List<MaintainMachDTO> machList = appMachMaintainPayMapper.selectByDeptIdAndTime(deptId, startDate, endDate, keyword);
        List<Integer> machIds = new ArrayList<>();
        for (MaintainMachDTO maintainMachDTO : machList) {
            machIds.add(maintainMachDTO.getMachId());
        }

        List<MaintainPayDTO> dayMaintainPayList = appMachMaintainPayMapper.selectDayMaintainPayDetail(machIds, startDate, endDate);
        // 存放每天费用详情
        Map<Date, List<MaintainPayDTO>> dayPayMap = new HashMap<>();
        // 存放每天费用总计
        Map<Date, Double> dayPayTotalMap = new HashMap<>();
        // 存放设备每天保养费用总计
        Map<Integer, List<MaintainPayDTO>> machPayMap = new HashMap<>();
        for (MaintainPayDTO maintainPayDTO : dayMaintainPayList) {
            Date date = maintainPayDTO.getDate();
            Integer machId = maintainPayDTO.getMachId();
            List<MaintainPayDTO> maintainDayPayDTOS = dayPayMap.get(date);
            if (maintainDayPayDTOS == null) {
                maintainDayPayDTOS = new ArrayList<>();
                dayPayMap.put(date, maintainDayPayDTOS);
            }
            maintainDayPayDTOS.add(maintainPayDTO);

            Double aDouble = dayPayTotalMap.get(date);
            if (aDouble == null) {
                dayPayTotalMap.put(date, maintainPayDTO.getPayValue());
            } else {
                dayPayTotalMap.put(date, aDouble + maintainPayDTO.getPayValue());
            }

            List<MaintainPayDTO> maintainPayDTOS = machPayMap.get(machId);
            if (maintainPayDTOS == null) {
                maintainPayDTOS = new ArrayList<>();
                machPayMap.put(machId, maintainPayDTOS);
            }
            maintainPayDTOS.add(maintainPayDTO);

        }

        // 每一天费用统计
        List<MaintainDayPayDTO> dayPayList = new ArrayList<>();
        Set<Date> dates = dayPayMap.keySet();
        for (Date date : dates) {
            MaintainDayPayDTO maintainDayPayDTO = new MaintainDayPayDTO();
            maintainDayPayDTO.setDate(date);
            maintainDayPayDTO.setPayTotal(dayPayTotalMap.get(date));
            maintainDayPayDTO.setPayList(dayPayMap.get(date));
            dayPayList.add(maintainDayPayDTO);
        }

        // 每个设备每天费用统计
        Set<Integer> machIdSet = machPayMap.keySet();
        Map<Integer, List<MaintainDayPayDTO>> machDayPayMap = new HashMap<>();
        for (Integer machId : machIdSet) {
            List<MaintainPayDTO> maintainPayDTOS = machPayMap.get(machId);
            Map<Date, Double> map = new HashMap<>();
            for (MaintainPayDTO maintainPayDTO : maintainPayDTOS) {
                Date date = maintainPayDTO.getDate();
                Double payValue = maintainPayDTO.getPayValue();
                Double aDouble = map.get(date);
                if (aDouble == null) {
                    map.put(date, payValue);
                } else {
                    map.put(date, aDouble + payValue);
                }
            }

            Set<Date> DateSet = map.keySet();
            for (Date date : DateSet) {
                List<MaintainDayPayDTO> maintainDayPayDTOS = machDayPayMap.get(machId);
                if (maintainDayPayDTOS == null) {
                    maintainDayPayDTOS = new ArrayList<>();
                    machDayPayMap.put(machId, maintainDayPayDTOS);
                }
                MaintainDayPayDTO data = new MaintainDayPayDTO();
                data.setDate(date);
                data.setPayTotal(map.get(date));
                maintainDayPayDTOS.add(data);
            }
        }

        // 设置每个设备每天的费用
        for (MaintainMachDTO maintainMachDTO : machList) {
            maintainMachDTO.setDayPayList(machDayPayMap.get(maintainMachDTO.getMachId()));
        }

        MaintainMonthReportDTO data = new MaintainMonthReportDTO();
        data.setMachList(machList);
        data.setDayPayList(dayPayList);
        return data;
    }

    @Override
    public MaintainYearReportDTO reportByYear(Integer deptId, Integer year, String keyword) throws BizException {
        logger.info("设备保养年报服务,deptId:{},year:{},keyword:{}", deptId, year, keyword);
        Date startDate = DateUtil.getYearBegin(year);
        Date endDate = DateUtil.getYearEnd(year);
        List<MaintainMachDTO> machList = appMachMaintainPayMapper.selectByDeptIdAndTime(deptId, startDate, endDate, keyword);
        List<Integer> machIds = new ArrayList<>();
        for (MaintainMachDTO maintainMachDTO : machList) {
            machIds.add(maintainMachDTO.getMachId());
        }

        List<MaintainPayDTO> dayMaintainPayList = appMachMaintainPayMapper.selectDayMaintainPayDetail(machIds, startDate, endDate);
        // 存放每月费用详情
        Map<Date, List<MaintainPayDTO>> monthPayMap = new HashMap<>();
        // 存放每月费用总计
        Map<Date, Double> monthPayTotalMap = new HashMap<>();
        // 存放设备每天保养费用总计
        Map<Integer, List<MaintainPayDTO>> machPayMap = new HashMap<>();
        for (MaintainPayDTO maintainPayDTO : dayMaintainPayList) {
            Date month = DateUtil.getMonthBegin(maintainPayDTO.getDate());
            Integer machId = maintainPayDTO.getMachId();
            List<MaintainPayDTO> maintainMonthPayDTOS = monthPayMap.get(month);
            if (maintainMonthPayDTOS == null) {
                maintainMonthPayDTOS = new ArrayList<>();
                monthPayMap.put(month, maintainMonthPayDTOS);
            }
            maintainMonthPayDTOS.add(maintainPayDTO);

            Double aDouble = monthPayTotalMap.get(month);
            if (aDouble == null) {
                monthPayTotalMap.put(month, maintainPayDTO.getPayValue());
            } else {
                monthPayTotalMap.put(month, aDouble + maintainPayDTO.getPayValue());
            }

            List<MaintainPayDTO> maintainPayDTOS = machPayMap.get(machId);
            if (maintainPayDTOS == null) {
                maintainPayDTOS = new ArrayList<>();
                machPayMap.put(machId, maintainPayDTOS);
            }
            maintainPayDTOS.add(maintainPayDTO);
        }

        // 每月费用统计
        List<MaintainMonthPayDTO> monthPayList = new ArrayList<>();
        Set<Date> dates = monthPayMap.keySet();
        for (Date month : dates) {
            MaintainMonthPayDTO maintainMonthPayDTO = new MaintainMonthPayDTO();
            maintainMonthPayDTO.setMonth(month);
            maintainMonthPayDTO.setPayTotal(monthPayTotalMap.get(month));
            maintainMonthPayDTO.setPayList(monthPayMap.get(month));
            monthPayList.add(maintainMonthPayDTO);
        }

        // 每个设备每月费用统计
        Set<Integer> machIdSet = machPayMap.keySet();
        Map<Integer, List<MaintainMonthPayDTO>> machMonthPayMap = new HashMap<>();
        for (Integer machId : machIdSet) {
            List<MaintainPayDTO> maintainPayDTOS = machPayMap.get(machId);
            Map<Date, Double> map = new HashMap<>();
            for (MaintainPayDTO maintainPayDTO : maintainPayDTOS) {
                Date month = DateUtil.getMonthBegin(maintainPayDTO.getDate());
                Double payValue = maintainPayDTO.getPayValue();
                Double aDouble = map.get(month);
                if (aDouble == null) {
                    map.put(month, payValue);
                } else {
                    map.put(month, aDouble + payValue);
                }
            }

            Set<Date> DateSet = map.keySet();
            for (Date date : DateSet) {
                List<MaintainMonthPayDTO> maintainMonthPayDTOS = machMonthPayMap.get(machId);
                if (maintainMonthPayDTOS == null) {
                    maintainMonthPayDTOS = new ArrayList<>();
                    machMonthPayMap.put(machId, maintainMonthPayDTOS);
                }
                MaintainMonthPayDTO data = new MaintainMonthPayDTO();
                data.setMonth(date);
                data.setPayTotal(map.get(date));
                maintainMonthPayDTOS.add(data);
            }
        }

        // 设置每个设备每月的费用
        for (MaintainMachDTO maintainMachDTO : machList) {
            maintainMachDTO.setMonthPayList(machMonthPayMap.get(maintainMachDTO.getMachId()));
        }

        MaintainYearReportDTO data = new MaintainYearReportDTO();
        data.setMachList(machList);
        data.setMonthPayList(monthPayList);
        return data;
    }

    @Override
    public void export(Integer deptId, Date startDate, Date endDate, String keyword) throws BizException {
        logger.info("导出设备保养月报服务,deptId:{},startDate:{},endDate:{},keyword:{}", deptId, startDate, endDate, keyword);
        String fileName = RandomUtil.getRandomFileName();
        Integer fileId = this.install(deptId, fileName, SUFFIX, MONTH_REPORT);
        // 获取数据
        List<MaintainMachDTO> machList = appMachMaintainPayMapper.selectByDeptIdAndTime(deptId, startDate, endDate, keyword);
        Map<Integer, Map<Date, Double>> machDayPayMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(machList)) {

            List<Integer> machIds = new ArrayList<>();
            for (MaintainMachDTO maintainMachDTO : machList) {
                machIds.add(maintainMachDTO.getMachId());
            }

            List<MaintainPayDTO> dayMaintainPayList = appMachMaintainPayMapper.selectDayMaintainPayDetail(machIds, startDate, endDate);
            // 存放设备每天保养费用总计
            Map<Integer, List<MaintainPayDTO>> machPayMap = new HashMap<>();
            for (MaintainPayDTO maintainPayDTO : dayMaintainPayList) {
                Integer machId = maintainPayDTO.getMachId();
                List<MaintainPayDTO> maintainPayDTOS = machPayMap.get(machId);
                if (maintainPayDTOS == null) {
                    maintainPayDTOS = new ArrayList<>();
                    machPayMap.put(machId, maintainPayDTOS);
                }
                maintainPayDTOS.add(maintainPayDTO);

            }

            // 每个设备每天费用统计
            Set<Integer> machIdSet = machPayMap.keySet();
            for (Integer machId : machIdSet) {
                List<MaintainPayDTO> maintainPayDTOS = machPayMap.get(machId);
                Map<Date, Double> map = new HashMap<>();
                for (MaintainPayDTO maintainPayDTO : maintainPayDTOS) {
                    Date date = maintainPayDTO.getDate();
                    Double payValue = maintainPayDTO.getPayValue();
                    Double aDouble = map.get(date);
                    if (aDouble == null) {
                        map.put(date, payValue);
                    } else {
                        map.put(date, aDouble + payValue);
                    }
                }
                machDayPayMap.put(machId, map);
            }
        }else{
            machList = new ArrayList<>();
        }

        try {
            // 获取模板
            ClassPathResource resource = new ClassPathResource("templates/machMaintainTemplate.xls");
            InputStream templateFileInputStream = resource.getInputStream();
            File tempFile = FileUtil.copyTemplateFile(templateFileInputStream);

            // 写数据
            FileInputStream fileInputStream = new FileInputStream(tempFile);
            HSSFWorkbook workbook = new HSSFWorkbook(fileInputStream);
            HSSFSheet sheet = workbook.getSheetAt(0);

            // 填充数据
            this.fillMonthReportData(sheet, machList, machDayPayMap, DateUtil.getDayList(startDate, endDate), MONTH_REPORT_TIME_FORMAT);

            // 保存excel
            FileOutputStream fos = new FileOutputStream(tempFile);
            workbook.write(fos);
            fos.flush();
            fos.close();

            // 上传oss
            String name = filePathConfig.getFilePath("mach/maintain/monthReport", fileName, SUFFIX);
            FileInputStream inputStream = new FileInputStream(tempFile);
            String upload = fileHandler.upload(name, inputStream, FileExpirationRules.DAYS_1);
            // 更新文件状态
            AppFileExportParam fileExportParam = new AppFileExportParam();
            fileExportParam.setFileUrl(upload);
            fileExportParam.setFileState(1);
            fileExportParam.setId(fileId);
            appExportService.update(fileExportParam);
        } catch (Exception e) {
            logger.error("导出保养月报失败", e);
        }

    }

    @Override
    public void export(Integer deptId, Integer year, String keyword) throws BizException {
        logger.info("导出设备保养年报服务,deptId:{},month:{},keyword:{}", deptId, year, keyword);
        String fileName = RandomUtil.getRandomFileName();
        Integer fileId = this.install(deptId, fileName, SUFFIX, YEAR_REPORT);
        // 获取数据
        Date startDate = DateUtil.getYearBegin(year);
        Date endDate = DateUtil.getYearEnd(year);
        List<MaintainMachDTO> machList = appMachMaintainPayMapper.selectByDeptIdAndTime(deptId, startDate, endDate, keyword);
        Map<Integer, Map<Date, Double>> machMonthPayMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(machList)) {
            List<Integer> machIds = new ArrayList<>();
            for (MaintainMachDTO maintainMachDTO : machList) {
                machIds.add(maintainMachDTO.getMachId());
            }

            List<MaintainPayDTO> dayMaintainPayList = appMachMaintainPayMapper.selectDayMaintainPayDetail(machIds, startDate, endDate);

            // 存放设备每天保养费用总计
            Map<Integer, List<MaintainPayDTO>> machPayMap = new HashMap<>();
            for (MaintainPayDTO maintainPayDTO : dayMaintainPayList) {
                Integer machId = maintainPayDTO.getMachId();
                List<MaintainPayDTO> maintainPayDTOS = machPayMap.get(machId);
                if (maintainPayDTOS == null) {
                    maintainPayDTOS = new ArrayList<>();
                    machPayMap.put(machId, maintainPayDTOS);
                }
                maintainPayDTOS.add(maintainPayDTO);
            }

            // 每个设备每月费用统计
            Set<Integer> machIdSet = machPayMap.keySet();
            for (Integer machId : machIdSet) {
                List<MaintainPayDTO> maintainPayDTOS = machPayMap.get(machId);
                Map<Date, Double> map = new HashMap<>();
                for (MaintainPayDTO maintainPayDTO : maintainPayDTOS) {
                    Date month = DateUtil.getMonthBegin(maintainPayDTO.getDate());
                    Double payValue = maintainPayDTO.getPayValue();
                    Double aDouble = map.get(month);
                    if (aDouble == null) {
                        map.put(month, payValue);
                    } else {
                        map.put(month, aDouble + payValue);
                    }
                }
                machMonthPayMap.put(machId, map);
            }
        }else{
            machList = new ArrayList<>();
        }

        try {
            // 获取模板
            ClassPathResource resource = new ClassPathResource("templates/machMaintainTemplate.xls");
            InputStream templateFileInputStream = resource.getInputStream();
            File tempFile = FileUtil.copyTemplateFile(templateFileInputStream);

            // 写数据
            FileInputStream fileInputStream = new FileInputStream(tempFile);
            HSSFWorkbook workbook = new HSSFWorkbook(fileInputStream);
            HSSFSheet sheet = workbook.getSheetAt(0);

            // 填充数据
            this.fillMonthReportData(sheet, machList, machMonthPayMap, DateUtil.getMonthListByYear(year), YEAR_REPORT_TIME_FORMAT);

            // 保存excel
            FileOutputStream fos = new FileOutputStream(tempFile);
            workbook.write(fos);
            fos.flush();
            fos.close();

            // 上传oss
            String name = filePathConfig.getFilePath("mach/maintain/yearReport", fileName, SUFFIX);
            FileInputStream inputStream = new FileInputStream(tempFile);
            String upload = fileHandler.upload(name, inputStream, FileExpirationRules.DAYS_1);
            // 更新文件状态
            AppFileExportParam fileExportParam = new AppFileExportParam();
            fileExportParam.setFileUrl(upload);
            fileExportParam.setFileState(1);
            fileExportParam.setId(fileId);
            appExportService.update(fileExportParam);
        } catch (Exception e) {
            logger.error("导出保养年报失败", e);
        }
    }

    /**
     * 填充数据
     *
     * @param sheet
     * @param machList
     */
    private void fillMonthReportData(HSSFSheet sheet, List<MaintainMachDTO> machList, Map<Integer, Map<Date, Double>> machPayMap, List<Date> dateList, String timeFormat) {
        // 设置第一行title
        HSSFRow row0 = sheet.createRow(0);
        HSSFCell cell00 = row0.createCell(0);
        cell00.setCellValue("设备编号");
        HSSFCell cell01 = row0.createCell(1);
        cell01.setCellValue("设备类型");
        HSSFCell cell02 = row0.createCell(2);
        cell02.setCellValue("费用总计");
        // 从第4列开始
        int cellIdx = 3;
        for (Date date : dateList) {
            HSSFCell cell = row0.createCell(cellIdx);
            cell.setCellValue(DateUtil.formatDate(date, timeFormat));
            cellIdx++;
        }

        // 填充数据
        int rowIdx = 1;
        for (MaintainMachDTO maintainDTO : machList) {
            HSSFRow row1 = sheet.createRow(rowIdx);
            HSSFCell cell10 = row1.createCell(0);
            cell10.setCellValue(maintainDTO.getMachCode());
            HSSFCell cell11 = row1.createCell(1);
            cell11.setCellValue(maintainDTO.getMachTypeName());
            HSSFCell cell12 = row1.createCell(2);
            cell12.setCellValue(maintainDTO.getPayTotal());

            // 从第4列开始
            int cellIdx1 = 3;
            for (Date date : dateList) {
                Double aDouble = machPayMap.get(maintainDTO.getMachId()).get(date);
                HSSFCell cell = row1.createCell(cellIdx1);
                cell.setCellValue(aDouble == null ? 0D : aDouble);
                cellIdx1++;
            }
            rowIdx++;
        }
    }


    /**
     * 安装要下载的文件
     *
     * @param deptId
     * @param fileName
     * @param suffix
     */
    private Integer install(Integer deptId, String fileName, String suffix, String fileDesc) {
        AppFileExportParam fileExport = new AppFileExportParam();
        fileExport.setDeptId(deptId);
        fileExport.setFileName(fileName);
        fileExport.setFileFormat(suffix.toUpperCase());
        fileExport.setFileState(0);
        fileExport.setFileDesc(fileDesc);
        Integer id = appExportService.install(fileExport);
        return id;
    }

}
